/**
 * @Creator: eyes
 * @Date: 2020/3/17
 * 业务线+应用+路径, 三个选择器的整合.
 */

import React, {useContext, useCallback, useState} from 'react';
import {Form} from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import {Select, message} from 'antd';
import {throttle} from 'lodash';

import {getFieldValues, getImportanceList} from '~/service/performance';
import {PAGER, SEARCH_WAIT_TIME} from '~/utils/const';
import {StoreContext} from '../data';
import {USER_FEATURE_ACTION_TYPES} from '../utils';

const {Item: FormItem} = Form;
const {Option: SelectOption} = Select;

const SCROLL_OFFSET = 50;

const noop = () => {
    // ...
};

const popUpContainer = triggerNode => triggerNode.parentElement;

// eslint-disable-next-line max-lines-per-function
export default ({getFieldDecorator, resetFields}) => {
    const {
        state: {
            selectedBusiness,
            businessList,
            selectedApplication,
            applicationList,
            selectedPath,
            pathList
        },
        dispatch,
    } = useContext(StoreContext);

    const [keyword, setKeyword] = useState('');
    const [loading, setLoading] = useState(false);
    const [pager, setPager] = useState(PAGER);
    const [hasNext, setHasNext] = useState(null);

    // 初次加载/滚动分页/搜索/搜索后分页的通用数据加载方法
    // searchMode: 是否为手动搜索的模式, true的话则替换当前list
    // keywordOnSearch: 用于搜索时直接传入keyword
    // newSelectedApplication: 新选择的「应用」, 还没有同步到全局, 所以需要参数传入
    const getPathList = useCallback(async ({
        searchMode = false, keywordOnSearch, newSelectedApplication,
    } = {}) => {
        setLoading(true);
        const {data: {values} = {}, pager: {pageSize, pageNum, count} = {}} = await getFieldValues({
            field: 'path',
            bizTypeName: selectedBusiness,
            bizName: newSelectedApplication || selectedApplication,
            keyword: searchMode ? keywordOnSearch : keyword,
            pager: searchMode ? PAGER : pager,

        });
        dispatch({
            type: USER_FEATURE_ACTION_TYPES.REGULAR_UPDATE,
            payload: {
                pathList: searchMode ? values : [...pathList, ...values],
            },
        });
        setPager({
            pageSize,
            pageNum: pageNum + 1,
        });
        setHasNext(pageSize * pageNum < count);
        setLoading(false);
    }, [selectedBusiness, selectedApplication, keyword, pager]);

    // 切换业务线的处理方法
    // UPDATE_BUSINESS Action内部会同步清空application和path的数据
    // 同时, 此处会重新获取application列表并设置
    const onBusinessChange = useCallback(async business => {
        dispatch({
            type: USER_FEATURE_ACTION_TYPES.UPDATE_BUSINESS,
            payload: {
                selectedBusiness: business,
            },
        });

        // 除了重置全局状态, 还需要重置Form内状态
        resetFields(['selectedApplication', 'selectedPath']);

        const {data: {values}} = await getFieldValues({
            field: 'biz_name',
            bizTypeName: business,
        });

        dispatch({
            type: USER_FEATURE_ACTION_TYPES.REGULAR_UPDATE,
            payload: {
                pathList: [],
                applicationList: values,
            },
        });
    }, []);

    // 切换应用的处理方法
    // UPDATE_APPLICATION Action内部会同步清空path的数据
    // 同时, 此处会重新获取path列表并设置
    const onApplicationChange = useCallback(application => {
        dispatch({
            type: USER_FEATURE_ACTION_TYPES.UPDATE_APPLICATION,
            payload: {
                selectedApplication: application,
            },
        });

        // 除了重置全局状态, 还需要重置Form内状态
        resetFields(['selectedPath']);

        // 重置pathList
        dispatch({
            type: USER_FEATURE_ACTION_TYPES.REGULAR_UPDATE,
            payload: {
                pathList: [],
            },
        });

        // 重新加载path列表
        getPathList({
            searchMode: true,
            keywordOnSearch: '',
            newSelectedApplication: application,
        });
    }, [getPathList]);

    // 滚动到底部时分页加载(常规态和搜索态, 或者说都携带keyword, 这样不用区分)
    const onPopupScroll = useCallback(e => {
        e.persist();
        const {target: {scrollTop, offsetHeight, scrollHeight}} = e;
        if (!loading && hasNext && (scrollHeight - (scrollTop + offsetHeight) < SCROLL_OFFSET)) {
            getPathList();
        }
    }, [hasNext, loading, getPathList]);

    // 触发搜索时, 加载新list全量替换旧list
    const onSearch = useCallback(throttle(keyword => {
        setKeyword(keyword);
        setPager(PAGER);
        getPathList({
            searchMode: true,
            keywordOnSearch: keyword,
        });
    }, SEARCH_WAIT_TIME, {leading: false}), [getPathList]);

    // 失去焦点时取消搜索相关状态.
    const onBlur = useCallback(() => {
        keyword && onSearch('');
    }, [keyword, onSearch]);

    // 切换路径的处理方法
    const onPathChange = useCallback(path => {
        keyword && onSearch('');
        dispatch({
            type: USER_FEATURE_ACTION_TYPES.REGULAR_UPDATE,
            payload: {
                selectedPath: path,
            },
        });
        // 3期需求，api判断当前所选的路径的指标排序，选择第一个
        const data = {
            bizTypeName: selectedBusiness,
            bizName: selectedApplication,
            path,
        };

        getImportanceList(data).then(res => {
            if (res.code === 0) {
                dispatch({
                    type: USER_FEATURE_ACTION_TYPES.REGULAR_UPDATE,
                    payload: {
                        targetType: res.data.sortedTargetTypes[0]
                    }
                });
            }
            else {
                message.error(res.msg);
            }
        });
    }, [keyword, onSearch]);

    const selectorFactoryConfig = [
        {
            label: '业务线',
            field: 'selectedBusiness',
            message: '业务线必填',
            onChange: onBusinessChange,
            list: businessList,
            width: 150,
            ...(selectedBusiness && {
                initialValue: selectedBusiness
            })
        },
        {
            label: '应用',
            field: 'selectedApplication',
            message: '应用必填',
            onChange: onApplicationChange,
            list: applicationList,
            width: 200,
            ...(selectedApplication && {
                initialValue: selectedApplication
            })
        },
        {
            label: '路径',
            field: 'selectedPath',
            message: '路径必填',
            onChange: onPathChange,
            list: pathList,
            width: 200,
            onPopupScroll,
            onSearch,
            onBlur,
            loading,
            ...(selectedPath && {
                initialValue: selectedPath
            })
        },
    ];

    return (
        selectorFactoryConfig.map((
            {label, field, initialValue, message, onChange, list, width, onPopupScroll, onSearch, onBlur, loading},
        ) => (
            <FormItem
                key={field}
                label={label}
                labelAlign="right"
            >
                {
                    getFieldDecorator(field, {
                        initialValue,
                        rules: [
                            {
                                required: true,
                                message
                            },
                        ],
                    })(
                        <Select
                            className="user-feature-select"
                            placeholder="请选择"
                            notFoundContent="暂无数据"
                            showSearch
                            optionFilterProp="children"
                            getPopupContainer={popUpContainer}
                            style={{width}}
                            filterOption={field !== 'selectedPath'}
                            loading={loading}
                            onChange={onChange}
                            onPopupScroll={onPopupScroll || noop}
                            onSearch={onSearch || noop}
                            onBlur={onBlur || noop}
                        >
                            {
                                list.map(item => (
                                    <SelectOption value={item} key={item} title={item}>
                                        {item}
                                    </SelectOption>
                                ))
                            }
                        </Select>,
                    )
                }
            </FormItem>
        ))
    );
};
